package com.anxin.aspect;

import com.anxin.annotation.RoleRequired;
import com.anxin.common.enums.RoleEnum;
import com.anxin.entity.SysUser;
import com.anxin.service.SysUserService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Map;

/**
 * 角色权限切面
 *
 * @author zengcheng
 * @date 2025/06/18
 */
@Aspect
@Component
public class RoleRequiredAspect {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SysUserService sysUserService;

    @Around("@annotation(roleRequired)")
    public Object checkRole(ProceedingJoinPoint joinPoint, RoleRequired roleRequired) throws Throwable {
        // 从 RequestContextHolder 获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            throw new RuntimeException("当前线程未绑定请求上下文");
        }

        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            throw new RuntimeException("未登录，无法访问");
        }

        token = token.substring(7);
        String redisKey = "user:auth:" + token;
        Object userObj = redisTemplate.opsForValue().get(redisKey);

        if (userObj == null) {
            throw new RuntimeException("登录已过期，请重新登录");
        }

        String requiredRole = roleRequired.value();
        String userRole = null;

        if (userObj instanceof Map<?, ?> map) {
            userRole = (String) map.get("roleId");
        } else if (userObj instanceof UserDetails userDetails) {
            userRole = userDetails.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority)
                    .filter(a -> a.startsWith("ROLE_"))
                    .map(a -> a.replace("ROLE_", ""))
                    .findFirst()
                    .orElseThrow(() -> new RuntimeException("权限不足"));

            // 如果需要 roleId，从数据库获取 SysUser
            SysUser sysUser = sysUserService.findByUsername(userDetails.getUsername());
            if (sysUser != null) {
                userRole = sysUser.getRoleId();
            }
        } else if (userObj instanceof SysUser sysUser) {
            userRole = sysUser.getRoleId();
        } else {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            // 从 SecurityContextHolder 中获取用户信息
            if (authentication != null && authentication.isAuthenticated() &&
                    authentication.getPrincipal() instanceof UserDetails userDetails) {
                userRole = userDetails.getAuthorities().stream()
                        .map(GrantedAuthority::getAuthority)
                        .filter(a -> a.startsWith("ROLE_"))
                        .map(a -> a.replace("ROLE_", ""))
                        .findFirst()
                        .orElseThrow(() -> new RuntimeException("权限不足"));
            } else {
                throw new RuntimeException("用户信息格式不支持");
            }
        }

        if (!requiredRole.equalsIgnoreCase(userRole)) {
            // 权限与枚举匹配，通过枚举获得角色名称
            RoleEnum requiredRoleName = RoleEnum.valueOf(requiredRole);
            RoleEnum userRoleName = RoleEnum.valueOf(userRole);
            throw new RuntimeException("权限不足，需要角色: " + requiredRoleName.getName() + "，当前角色: " + userRoleName.getName());
        }

        return joinPoint.proceed();
    }
}
